package com.kaibes.web.thymeleaf;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;
import org.thymeleaf.IEngineConfiguration;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.templateresource.SpringResourceTemplateResource;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.util.ContentTypeUtils;

//templateResolver
@Component("defaultTemplateResolver")
public class AutoTemplateResolver extends SpringResourceTemplateResolver  {

    public final static String prefix1 = "classpath:/";
    public final static String prefix2 = "file:";
    
    @Value("${spring.thymeleaf.prefix:templates/}")
    private String prefix;
    @Value("${spring.thymeleaf.suffix:.html}")
    private String suffix;
    @Value("${spring.thymeleaf.mode:HTML}")
    private String mode;
    @Value("${spring.thymeleaf.encoding:UTF-8}")
    private String encoding;
    @Value("${spring.thymeleaf.cache:true}")
    private boolean cache;
    @Value("${spring.thymeleaf.template-resolver-order:0}")
    private int order;
    @Value("${spring.thymeleaf.check-template-location:false}")
    private boolean check;
    
    private ApplicationContext applicationContext;
    private List<ClassLoader> classLoaderList = new ArrayList<>();
    private ThreadLocal<String> pathLocal = new ThreadLocal<>();
    
    public void addClassLoader(ClassLoader classLoader) {
        classLoaderList.add(classLoader);
    }
    
    public void removeClassLoader(ClassLoader classLoader) {
        classLoaderList.remove(classLoader);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        super.setApplicationContext(applicationContext);
        this.applicationContext = applicationContext;
        setPrefix(prefix);
        setSuffix(suffix);
        setTemplateMode(TemplateMode.parse(mode));
        setCharacterEncoding(encoding);
        setCacheable(cache);
        if (order != 0) {
        	setOrder(order);
        }
    	setCheckExistence(check);
    }
    
    @Override
    protected String computeResourceName(IEngineConfiguration configuration, String ownerTemplate, String template,
            String prefix, String suffix, boolean forceSuffix, Map<String, String> templateAliases,
            Map<String, Object> templateResolutionAttributes) {
    	
        if (template.startsWith(prefix1)) {
            template = template.substring(10);
        }
        if (template.startsWith("/")) {
            template = template.substring(1);
        }
        if (template.startsWith(prefix)) {
            template = template.substring(10);
        }
        String path = super.computeResourceName(configuration, ownerTemplate, template, prefix, suffix, forceSuffix, templateAliases, templateResolutionAttributes);
        if (getResource(prefix2+path).exists()) {
            path = prefix2+path;
        } else if (getResource(prefix1+path).exists()) {
            path = prefix1+path;
        }
        pathLocal.set(path);
        return path;
        
    }
    
    @Override
    protected TemplateMode computeTemplateMode(IEngineConfiguration configuration, String ownerTemplate,
            String template, Map<String, Object> templateResolutionAttributes) {
        template = pathLocal.get();
        
        if (template.endsWith(".xml")) {
            return TemplateMode.XML;
        }
        if (template.endsWith(".html")) {
            return TemplateMode.HTML;
        }
        if (template.endsWith(".txt")) {
            return TemplateMode.TEXT;
        }
        if (template.endsWith(".js")) {
            return TemplateMode.JAVASCRIPT;
        }
        if (template.endsWith(".css")) {
            return TemplateMode.CSS;
        }
        if (template.endsWith(".raw")) {
            return TemplateMode.RAW;
        }
        if (!getForceTemplateMode()) {
            final String templateResourceName = template;
            final TemplateMode autoResolvedTemplateMode = ContentTypeUtils.computeTemplateModeForTemplateName(templateResourceName);
            if (autoResolvedTemplateMode != null) {
                return autoResolvedTemplateMode;
            }
        }
        return getTemplateMode();
    }
    
    @Override
    protected ITemplateResource computeTemplateResource(IEngineConfiguration configuration, String ownerTemplate,
            String template, String resourceName, String characterEncoding, Map<String, Object> templateResolutionAttributes) {
        return new SpringResourceTemplateResource(getResource(resourceName), characterEncoding);
    }
    
    private Resource getResource(String path) {
        if (path.startsWith(prefix1)) {
            String temp = path.substring(11);
            for (ClassLoader classLoader : classLoaderList) {
                URL url = classLoader.getResource(temp);
                if (url != null) {
                    return new ClassPathResource(temp, classLoader);
                }
            }
        }
        return applicationContext.getResource(path);
    }
    
}
